// G1_Ilum.cpp : Defines the entry point for the console application.
//
#pragma once

#include "SceneLoader.h"
#include <GL\glui.h>
#include <math.h>
#include <iostream>

using namespace std;

#define DIMX 500
#define DIMY 500
#define INITIALPOS_X 200
#define INITIALPOS_Y 200

float xy_aspect;

float view_rotate[16] =	{ 1,0,0,0,
						  0,1,0,0,
						  0,0,1,0,
						  0,0,0,1};

float obj_pos[] = { 0.0, 0.0, 0.0 };
double axis_radius_begin =  0.2;
double axis_radius_end   =  0.0;
int axis_nslices = 8;
int axis_nstacks = 1;
double orig_radius = 0.5;
int orig_slices = 8;
int orig_stacks =16;
float mat1_shininess[] = {128.0}; 
float mat1_specular[] = {0.4, 0.4, 0.4, 1.0};
float mat1_diffuse[] =  {0.6, 0.6, 0.6, 1.0};
float mat1_ambient[] =  {0.6, 0.6, 0.6, 1.0};
double dimx= 6.0;
double dimy= 2.0;
double dimz=10.0;

int main_window;
GLUI  *glui2;

SceneLoader *scene;
RGBpixmap pixmap;
GLUquadric* glQ;
bool changeMaterial = false;
char currentKey;
bool keyPress[256];

int actualCam = 0;
int actualLight = 0;
int freedom = 0;
int wireframe = 0;
int onOrOff = 0;

vector<char> keys;
size_t keySize;
char actualKey;

void drawAxis(float axisLength)
{
	glColor3f(1.0,1.0,1.0);		
	gluSphere(glQ, orig_radius, orig_slices, orig_stacks);

	glColor3f(1.0,0.0,0.0);
	glPushMatrix();
	glRotated(90.0, 0.0,1.0,0.0 );
	gluCylinder(glQ, axis_radius_begin, axis_radius_end, axisLength, axis_nslices, axis_nstacks); 
	glPopMatrix();

	glColor3f(0.0,1.0,0.0);
	glPushMatrix();
	glRotated(-90.0, 1.0,0.0,0.0 );
	gluCylinder(glQ, axis_radius_begin, axis_radius_end, axisLength, axis_nslices, axis_nstacks);  
	glPopMatrix();
	
	glColor3f(0.0,0.0,1.0);
	glPushMatrix();
	gluCylinder(glQ, axis_radius_begin, axis_radius_end, axisLength, axis_nslices, axis_nstacks); 
	glPopMatrix();

	glColor3f(0.65,0.65,0.65);
}


void display(void)
{	
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	glFrustum( -xy_aspect*.04, xy_aspect*.04, -.04, .04, .1, 50.0 );

	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity();
	
	if(freedom)
	{
		glTranslated(0.0,0.0,-25.0);
		glTranslatef( obj_pos[0], obj_pos[1], -obj_pos[2] );    
		glRotated(20.0, 1.0,0.0,0.0 );
		glRotated(-45.0, 0.0,1.0,0.0 );	
		glMultMatrixf( view_rotate );
	}
	else
		scene->viewsMap[actualCam]->applyView();

	if(!wireframe)
		glPolygonMode(GL_FRONT, GL_FILL);
	else
		glPolygonMode(GL_FRONT, GL_LINE);
	
	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

	glEnable(GL_COLOR_MATERIAL);
		drawAxis(scene->s->getLengthAxis());
	glDisable(GL_COLOR_MATERIAL);

	glMaterialfv(GL_FRONT, GL_SHININESS, mat1_shininess);
	glMaterialfv(GL_FRONT, GL_SPECULAR,  mat1_specular);
	glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat1_diffuse);
	glMaterialfv(GL_FRONT, GL_AMBIENT,   mat1_ambient);
	
	scene->runScene(changeMaterial, currentKey);
	if(changeMaterial)
	{
		currentKey = '\0';
		changeMaterial = false;
	}

	if(!onOrOff)
	{
		scene->lightsMap[actualLight]->turnOff();
	}
	else
		scene->lightsMap[actualLight]->turnOn();

	glutSwapBuffers();
   
	glFlush();
}

/* Mouse handling */
void processMouse(int button, int state, int x, int y)
{
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{	 
	}
	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
	{	
	}
	
	glutPostRedisplay();
	
}

void processMouseMoved(int x, int y)
{
	glutPostRedisplay();				
}

void processPassiveMouseMoved(int x, int y)
{

	glutPostRedisplay();				
}

void reshape(int w, int h)
{
	int tx, ty, tw, th;

	GLUI_Master.get_viewport_area( &tx, &ty, &tw, &th );
	glViewport( tx, ty, tw, th );
	xy_aspect = (float)tw / (float)th;

	glutPostRedisplay();
}

void changeMat(unsigned char key)
{
	for(size_t i = 0; i < keySize; i++)
	{
		if(key == keys[i])
		{
			changeMaterial = true;
			currentKey = key;
		}
	}
}

void keyboard(unsigned char key, int x, int y)
{
	changeMat(key);

	switch(key)
	{
		default:
			break;
	}

}


void myGlutIdle( void )
{
  if ( glutGetWindow() != main_window ) 
    glutSetWindow(main_window);  

  glutPostRedisplay();
}

void inicializacao()
{
	glFrontFace(GL_CCW);
	glDepthFunc(GL_LEQUAL);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);

	glQ = gluNewQuadric();
	scene->i->applyIllumination();
	glEnable(GL_LIGHTING);

	for(size_t i = 0; i < scene->lightsMap.size(); i++)
	{
		scene->lightsMap[i]->applyLight();
	}

	glShadeModel(GL_SMOOTH);	
	glPolygonMode(GL_FRONT, GL_FILL);

	map<string, Texture*>::iterator it;

	for(it = scene->texturesMap.begin(); it != scene->texturesMap.end(); it++)
	{
		(*it).second->applyTexture();
	}
}

int main(int argc, char* argv[])
{
	scene = new SceneLoader("greenhill.xml");

	scene->loadScene();

	const string rootID = scene->s->getID();
	Component* startingComponent = scene->componentsMap[rootID];
	startingComponent->constructTree(scene->primitivesMap, scene->componentsMap);

	keys = startingComponent->getKeys();
	keySize = keys.size();

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowSize (DIMX, DIMY);
	glutInitWindowPosition (INITIALPOS_X, INITIALPOS_Y);
	main_window = glutCreateWindow (argv[0]);
 
   glutDisplayFunc(display);
   GLUI_Master.set_glutReshapeFunc(reshape);
   GLUI_Master.set_glutKeyboardFunc (keyboard);
   GLUI_Master.set_glutMouseFunc(processMouse);
   glutMotionFunc(processMouseMoved);
   glutPassiveMotionFunc(processPassiveMouseMoved);   
   GLUI_Master.set_glutSpecialFunc( NULL );
   
	glui2 = GLUI_Master.create_glui_subwindow( main_window, GLUI_SUBWINDOW_BOTTOM );
	glui2->set_main_gfx_window( main_window );

	GLUI_Rotation *view_rot = glui2->add_rotation( "Rotacao", view_rotate );
	view_rot->set_spin( 1.0 );
	glui2->add_column( false );

	GLUI_Translation *trans_z = 
	glui2->add_translation( "Zoom", GLUI_TRANSLATION_Z, &obj_pos[2] );
	trans_z->set_speed( .02 );
	glui2->add_column(false);

	GLUI_Panel* panelX = glui2->add_panel("Views", GLUI_PANEL_EMBOSSED);
	glui2->add_column(false);
	GLUI_Panel* panelLights = glui2->add_panel("Lights", GLUI_PANEL_EMBOSSED);

	GLUI_Listbox *views_box = glui2->add_listbox_to_panel(panelX, "Current", &actualCam);
	for(int i = 0; i < scene->viewsMap.size(); i++)
	{
		views_box->add_item(i, (char*)(scene->viewsMap[i]->getID()).c_str());
	}

	GLUI_Listbox *lights_box = glui2->add_listbox_to_panel(panelLights, "Current", &actualLight);
	for(int i = 0; i < scene->lightsMap.size(); i++)
	{
		lights_box->add_item(i, (char*)(scene->lightsMap[i]->getID()).c_str());
	}

	GLUI_Checkbox* turnAround = glui2->add_checkbox_to_panel(panelLights, "Switch", &onOrOff);

	GLUI_Checkbox* free = glui2->add_checkbox_to_panel(panelX, "Free View", &freedom);
	GLUI_Checkbox* wire = glui2->add_checkbox_to_panel(panelX, "Wireframe", &wireframe);
	
	GLUI_Master.set_glutIdleFunc( myGlutIdle );
   
	inicializacao();
   
	glutMainLoop();

	return 0;
}
